Pacote Shiny

André, Bruno, Caio, Gabriel e João Gabriel

Importando pacotes que serão utilizados para elaboração dos códigos

if(!require("pacman")) install.packages("pacman")
pacman::p_load("shiny",
               "tidyverse",
               "babynames",
               "DT",
               "shinythemes",
               "gapminder",
               "shinydasboard")

Sumário

  1. Introdução
  2. Estrutura Básica e Geral de um App Shiny
  3. Tipos de Inputs e Outputs
  4. Programação Reativa
  5. Tipos de Layout e Temas
  6. Dashboards no Shiny

Introdução

Funcionalidade

Shiny é um pacote do R (também disponível para o Python) que permite a criação e publicação de aplicações web sem necessidade de conhecimento prévio em HTML, CSS e JavaScript;

Ou seja, a proposta é facilitar a criação de apps web somente com conhecimento em R.

Estrutura Básica de um App Shiny

Em essência, um App Shiny é gerado a partir de dois objetos e a chamada de uma função:

  • UI (Interface do Usuário)

  • Server

  • Função shinyApp(ui, server)

library(shiny)

ui <- fluidPage(
  
)

server <- function(input, output) {
  
}

shinyApp(ui = ui, server = server)

UI - Interface do Usuário

UI: Definição

O objeto UI é geralmente inicializado pela função fluidPage(), que gerá uma página HTML vazia (também podem ser usadas outras funções para inicializar o UI);

São definidos os tipos de inputs (valores de entrada) e outputs (valores de saída) que o App Shiny apresentará, assim como também a formatação, layout.

ui <- fluidPage(
  titlePanel(),
  sidebarLayout(
    sidebarPanel(
    ),
    mainPanel(
    )
  )
)

Tipos de Input

Estrutura Comum

Há inúmeros tipos de input disponíveis no Shiny.De todo modo, para que sejam reconhecidos e processados, todos ele precisam de dois parâmetros em comum:

  • Parâmetro “inputId”: Trata-se de uma string simples e única que será armazenada dentro da lista “input” que é parâmetro da função server(input, output). Desse modo, deve-se utilizar id´s diferentes para referenciar diferentes inputs;

  • Parâmetro “label”: Trata-se do rótulo/mensagem/instrução que irá aparecer no App Shiny, orientando o usuário sobre como ele deve interagir com as opções de input dadas.

selectInput(inputId = "input1",   # String identificadora do Input
            label = "Selecione uma das opções abaixo.",
            choices = c("A", "B", "C"))

sliderInput(inputId = "input2", # String identificadora do Input
            label = "Selecione um valor de interesse",
            value = 1925,
            min = 1900,
            max = 2000)

Tipos de Input

selectInput()

Dada uma listagem de opções fornecidas, é solicitado ao usuário selecionar uma ou algumas das opções dadas.

selectInput(inputId = 'input1',
            label = 'Escolha uma das opções',
            choices,
            selected = NULL,
            multiple = FALSE,
            ...)

Tipos de Input

checkboxGroupInput()

Semelhante à função selectInput(), mas com uma aparência levemente diferente, e permite selecionar, por padrão, múltiplas opções.

checkboxGroupInput(inputId,
              label,
              choices,
              selected = NULL,
              ...)

Tipos de Input

actionButton()

Pede ao usuário que aperte um botão interativo para que uma certa ação seja realizada no aplicativo.

actionButton(inputId = 'input1',
             label = 'Aperte o Botão para...',
             icon,
             width,
             ...)

Tipos de Input

sliderInput()

A partir de uma barra de rolagem (horizontal), o usuário é informado para selecionar um número dentro de um intervalo de valores estabelecido

sliderInput(inputId,
            label,
            min,
            max,
            value = "valor_default/padrao",
            ...)

Tipos de Input

textInput()

Trata-se de uma função para inserção de inputs em forma de texto.

textInput(inputId,
          label = "Informe seu nome",
          value = "Nome",
          width = NULL,
          placeholder = NULL)

Tipos de Input

passwordInput()

Semelhante a função tenxtInput(), com a diferença que o input informado aparecerá com tarjas (“*”)

passwordInput(input,
              label,
              value,
              width = NULL,
              placeholder = NULL)

Tipos de Input

Além das funções input citadas acima, há várias outras tais como:

dateInput(inputId = 'data1', label = 'Escolha uma data de interesse', value = NULL,
          min = NULL, max = NULL,
          format = "yyyy-mm-dd", ...)
dateRangeInput(inputId = 'int_data', label = 'Defina um intervalo de datas',
               start = NULL, end = NULL, min = NULL,
               max = NULL, format = "yyyy-mm-dd", ...)
numericInput(inputId = 'numero', label = 'Selecione um valor',
             value, min,
             max, step,
             width = NULL)
fileInput(inputId,label,
          multiple = FALSE, accept = NULL,
          width = NULL,
          ...)

Outputs

Tipos de Output

  • Os tipos de output são definidos no primeiro objeto, a UI (interface de usuário).

  • Assim como os inputs, no output também exigem uma identificação:

    • Parâmetro ‘outputId’.
dataTableOutput(outputId = "dataframe")   # Define um dataframe como output

htmlOutput(outputId = "html") # Define um documento HTML como output

imageOutput(outputId = 'image') # Define uma imagem como output

plotOutput(outputId = 'plot') # Define um gráfico como output

tableOutput(outputId = 'tabela') # Define uma tabela como output

textOutput(outputId = 'texto') # Define um texto como output
...

Tipos de Output

  • Feito isso, para que o(s) output(s) definido(s) seja(m) devidamente executado(s) e processado(s) pelo R, faz-se necessário também o uso das render functions (funções de renderização); por exemplo, “renderText({})”;

  • Estas são definidas no objeto Server (falaremos sobre logo a seguir).

ui3 <- fluidPage( 
  textInput("name", "Enter a name:"),
  textOutput("greeting")
)

server3 <- function(input, output, session){
  output$greeting <- renderText({
    paste("Do you prefer dogs or cats,", input$name, "?")
  })
}
  
shinyApp(ui = ui3, server = server3)

Server

Server

  • É nesse objeto que ocorre efetivamente a interação entre os inputs e outputs definidos no UI. Acessamos cada um dos inputs e outputs definidos usando o operador “$” em conjuto com os parâmetros input e/ou ouput do objeto server, ou seja:
    • input$input_id e output$output_id;

Estrutura Básica do Server

server <- function(input, output, session) {
  
  output$output_id
  
  input$input_id
  

}
  • Mas como exatamente cada elemento do parâmetro output pode interagir com um input?”

Server

Render Functions

  • Para que a interação entre input e output efetivamente ocorra, deve-se utilizar o que chamamos de “render functions”, que possuem variados tipos, e são escolhidas com base nos tipos de output que foram definidos no UI (tabela, gráfico, dataframe…). Ou seja, as render functions são o objeto intermediário entre inputs e outputs.

As render functions (funções de renderização) são os objetos que irão efetivamente explicitar os outputs previamente definidos no UI;

server <- function(input, object) {
  output$output_id <- render**function**({
    
    "blackbox"(input$input_id) ## Dentro da render function, algum input armazenado dentro do parâmetro
                              # input como "input_id" recebe algum tipo de transformação de maneira a gerar
                              # um output
    })

}

Server

Render Functions

Alguns exemplos:

Output Render Function
textOutput renderText({})
plotOutput renderPlot({})
tableOutput renderTable({})
imageOutput renderImage({})

Elas possibilitam também a utilização de outros pacotes interativos possuem suporte para renderizar seus outputs no Shiny. Entre eles DT, Plotly e Leaflet

Exemplos de Render Functions

renderPlot()

server <- function(input, output, session){
  output$hist_waiting <- renderPlot({
    hist(faithful$waiting,
         breaks = input$nb_bins,
         col = 'steelblue')
  })
}

Exemplos de Render Functions

renderPlot() + pacote plotly

server <- function(input, output, session){
  # Função para plotar tendências de um nome
  plot_trends <- function(){
    babynames %>% 
      filter(name == input$name) %>% 
      plotly::plot_ly(, x = ~year, y = ~n, type = "bar")
  }
  output$plot_trendy_names <- plotly::renderPlotly(plot_trends())
}

Exemplos de Render Functions

renderTable() + pacote DT

server <- function(input, output){
  output$babynames_table <- DT::renderDT({
    babynames %>% 
      dplyr::slice_sample(prop = .1) %>% 
      DT::datatable()
  })
}

Tipos de Layout e Temas

Layout

Na estrutura básica os inputs são dispostos um embaixo do outro, visando melhorar a visualização do usuário, existem funções que alteram esse padrão:

  • titlePanel(): que implementa um título pro app:

  • sidebarLayout(): essa cria o layout geral de saída e que comporta opcções de disposição de inputs e outputs.

titlePanel()

Aqui a função tem como parametros apenas o label que está em formato de string

ui <- fluidPage(
  titlePanel("Histograma")
)

sidebarLayout()

No layout gerado por essa função divide-se a tela de saída em duas:

  • sidebarPanel(): aqui estarão as entradas do usário;

  • mainPanel(): nesta área são as saídas geradas no server.

inputPanel(
  titlePanel("Baby Name Explorer"),
  sidebarLayout(
    sidebarPanel(
      textInput('name', 'Enter Name', 'David')),
    mainPanel(  
      plotOutput('trend')))
)

Baby Name Explorer

sidebarPanel()

Neste espaço as opções de inputs vistas anteriormente são posicionadas no lado esquerdo da interface;

São possíveis envolopar mais de uma opção de input.

 inputPanel(
   titlePanel('BMI Calculator'),
   sidebarLayout(
     sidebarPanel(
       textInput('name', 'Enter your name'),
       numericInput('height', 'Enter height (in m)', 1.5, 1, 2, step = 0.1),
       numericInput('weight', 'Enter weight (in Kg)', 60, 45, 120),
       actionButton("show_bmi", "Show BMI")
     ),
     mainPanel()
    )
   )

BMI Calculator

mainPanel()

Nessa função vamos incluir as saídas que foram processadas no server e adicionadas no lado direito da interface;

Aqui caso haja uma saída basta apenas utilizar:

 ui <- fluidPage(
   titlePanel('BMI Calculator'),
   sidebarLayout(
     sidebarPanel(
       textInput('name', 'Enter your name'),
       numericInput('height', 'Enter height (in m)', 1.5, 1, 2, step = 0.1),
       numericInput('weight', 'Enter weight (in Kg)', 60, 45, 120),
       actionButton("show_bmi", "Show BMI")
     ),
     mainPanel(
       textOutput("bmi")
     )
   )
 )

tabsetPanel()

Caso existam mais de uma saída e deseja-se criar abas para exibir os resultados vamos usar essa função.

 ui <- fluidPage(
   titlePanel("UFO Sightings"),
   sidebarPanel(
     selectInput("state", "Choose a U.S. state:", choices = unique(usa_ufo_sightings$state)),
     dateRangeInput("dates", "Choose a date range:",
                    start = "1920-01-01",
                    end = "1950-01-01"
     )
   ),
   mainPanel(
     tabsetPanel(
       tabPanel("Plot", plotOutput("shapes")),
       tabPanel("Table", tableOutput("duration_table"))
     )
   )
 )

Dashboard

  • Uma das formas de se criar dashboards utilizando as funcionalidades do Shiny é utilizando o pacote shinydashboard
library(shinydashboard)

header <- dashboardHeader(title = "My first dashboard")

sidebar <- dashboardSidebar()

body <- dashboardBody()

ui <- dashboardPage(header, sidebar, body)

server <- function(input, output){
  
  shinyApp(ui, server)

Dashboard

  • Mudando parâmetros no header
  # Definindo novos parâmetros no header
  header <- dashboardHeader(title = "My first dashboard",
                            titleWidth = 300,
                            dropdownMenu(type = "messages"),
                            dropdownMenu(type = "notifications")
                            
  )
  
  ui <- dashboardPage(header, sidebar, body)
  
  server <- function(input, output) {
  }
  
  shinyApp(ui, server)

Dashboard

  • Mudando parâmetros na sidebar
# Definindo a sidebar e seus parâmetros
  sidebar <- dashboardSidebar(width = 300,
                              sidebarMenu(
                                id = "pages",
                                menuItem("Many charts", tabName = "charts",
                                         icon = icon("chart-line")),
                                menuItem("Statistics", tabName = "stats",
                                         icon = icon("file-excel"))
                              ))
  
  ui <- dashboardPage(header, sidebar, body)
  
  server <- function(input, output) {
  }
  
  shinyApp(ui, server)

Dashboard

  • É possível adicionar subtabs na sidebar
  # Adicionando subtabs na sidebar
  sidebar <- dashboardSidebar(
    width = 300,
    sidebarMenu(
      id = "pages",
      menuItem("Many charts", tabName = "charts",
               icon = icon("chart-line")),
      menuItem("Statistics", tabName = "stats",
               icon = icon("file-excel"),
               menuSubItem("Team 1", tabName = "team1",
                           icon = icon("user")))
    ))
  
  ui <- dashboardPage(header, sidebar, body)
  
  server <- function(input, output) {
  }
  shinyApp(ui, server)

Dashboard

  • Assim como adicionar inputs
# Adicionando inputs na sidebar
  
  sidebar <- dashboardSidebar(width = 300,
                              sidebarMenu(
                                id = "pages",
                                menuItem("Many charts", tabName = "charts",
                                         icon = icon("chart-line")),
                                menuItem("A couple of checkboxes",
                                         checkboxGroupInput("checkboxes",
                                                            "Days of the week",
                                                            choices = c("Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun")))
                              ))
  
  ui <- dashboardPage(header, sidebar, body)
  
  server <- function(input, output) {
  }
  
  shinyApp(ui, server)

Dashboard

  • Por fim é possível desativar a sidebar
  # Desativando a sidebar
  
  sidebar <- dashboardSidebar(disable = TRUE)
  
  ui <- dashboardPage(header, sidebar, body)
  
  server <- function(input, output) {
  }
  
  shinyApp(ui, server)

Programação Reativa

O que é reatividade?

Resumidamente, reatividade em programação é o conceito que torna possível a interação dinâmcica do usuário com o programa, no qual o que é efetivamente executado e exibido se baseia no acompanhamento das mudanças de determinados valores. Por exemplo, se um determinado input muda, um novo cálculo deve ser executado e um novo output gerado.

Programação Reativa

Como funciona a reatividade em apps Shiny?

A reatividade se baseia em uma paradigma diferente de programção, chamado de declarativo. No Shiny, declaramos dentro da função server() quando e quais códigos devem ser executados a depender de cada nova situação. Podemos representar as relações de dependência entre input e output e os consequentes fluxos de execução nesses casos através de um diagrama de reatividade.

Programação Reativa

Diagrama de Reatividade

exemplo:

# ui
ui <- fluidPage(
  selectInput(
    inputId = "variavel_A",
    label = "Variável A",
    choices = variaveis
  ),
  plotOutput(outputId = "histograma_A"),
  selectInput(
    inputId = "variavel_B",
    label = "Variável B",
    choices = variaveis,
    selected = variaveis[2],
  ),
  plotOutput(outputId = "histograma_B")
)

Programação Reativa

Diagrama de Reatividade

exemplo:

# server
server <- function(input, output, session) {
  output$histograma_A <- renderPlot({
    print("Gerando histograma A...")
    hist(mtcars[[input$variavel_A]], main = "Histograma A")
  })
  output$histograma_B <- renderPlot({
    print("Gerando histograma B...")
    hist(mtcars[[input$variavel_B]], main = "Histograma B")
  })
}

# app
shinyApp(ui, server)

Programação Reativa

Diagrama de Reatividade

diagrama de reatividade do exemplo